package net.sf.calibur.ai.pathfinder;

import java.util.Collection;

/**
 * 三种不同实现方法的OpenList测试数据，相同地图（复杂）寻路10000次。
 * 1. SimpleOpenList:        69156 67441 68731 67389
 * 2. BinaryHeapOpenList:    53732 53246 53516 53157
 * 3. DynamicSortedOpenList: 81021 79187 80200 78665
 * 可以看出二叉堆的确是有优势，其中DynamicSorted表现最差，是因为每次都进行了全排序，
 * 这其实是没必要的，OpenList每次poll()只需要找到F值最小的，并不需要对整个List进行排序，
 * 所以每次poll()时遍历一次所有节点的SimpleOpenList都比DynamicSorted耗时少。
 * @author gaobo.benny
 *
 */
public class FinderContext {
	private final static int CACHED_NODES_LEN = 100;
	
	private boolean achieved = false;
	private OpenList openList = new BinaryHeapOpenList();
	private Table closeMap = new Table();
	private AStarNode source = null, target = null;
	private TiledMap map = null;
	private Table cachedNodes = new Table();

	public FinderContext() {
		for (int y = 0; y < CACHED_NODES_LEN; ++y) {
			for (int x = 0; x < CACHED_NODES_LEN; ++x) {
				cachedNodes.put(x, y, new AStarNode(x, y));
			}
		}
	}
	
	public AStarNode getNode(int x, int y) {
		AStarNode node = cachedNodes.get(x, y);
		if (node == null) {
			node = new AStarNode(x, y);
			cachedNodes.put(x, y, node);
		}
		
		return node;
	}
	
	public void reset(TiledMap map, AStarNode source, AStarNode target) {
		this.source = source;
		this.target = target;
		this.map = map;
		
		achieved = false;
		openList.clear();
		closeMap.clear();
		for (AStarNode node : cachedNodes.values()) {
			node.clear();
		}
		
		// 把起点(source)加入到openList
		openList.add(source);
	}
	
	public Collection<AStarNode> getOpenList() {
		return openList.values();
	}
	
	public AStarNode getMinFNode() {
		return openList.poll();
	}
	
	public AStarNode getOpenNode(AStarNode node) {
		return openList.get(node.getX(), node.getY());
	}
	
	public boolean isClosedListContains(AStarNode node) {
		return isClosedListContains(node.getX(), node.getY());
	}
	
	public boolean isClosedListContains(int x, int y) {
		return closeMap.contains(x, y);
	}
	
	public boolean isEmpty() {
		return openList.size() == 0;
	}
	
	public AStarNode getSource() {
		return source;
	}

	public AStarNode getTarget() {
		return target;
	}
	
	public TiledMap getMap() {
		return map;
	}

	public boolean isAchieved() {
		return achieved;
	}
	
	public void achieved() {
		achieved = true;
	}
	
	public void addToClosedList(AStarNode node) {
		closeMap.put(node.getX(), node.getY(), node);
	}
	
	public void addToOpenList(AStarNode node) {
		openList.add(node);
	}
	
	public void touchNeighbor(AStarNode neighbor, AStarNode current, AStarNode target) {
		openList.touchNeighbor(neighbor, current, target);
	}
}
